/*
 * Copyright (C) 2008 The Android Open Source Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/** @defgroup poll Poll
* @ingroup libc
*/

#ifndef _POLL_H_
#define _POLL_H_

#include <sys/cdefs.h>
#ifndef __LITEOS__
#include <linux/poll.h>
#else
#include <liteos/poll.h>
#endif
#include <signal.h> /* For sigset_t. */
#include <time.h> /* For timespec. */

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */


typedef unsigned int nfds_t;

/**
* @ingroup  poll
* @par Description:
*
* The poll function provides applications with a mechanism for multiplexing input/output over a set of file descriptors. For each member of the
* array pointed to by fds, the poll examines the given file descriptor for the event(s) specified in events. The poll identifies those file descriptors
* on which an application can read or write data, or on which certain events have occurred.\n\n
*
* The fds argument specifies the file descriptors to be examined and the events of interest for each file descriptor. It is a pointer to an array with
* one member for each open file descriptor of interest. The array's members are pollfd structures within which fd specifies an open file descriptor
* and events and revents are bitmasks constructed by OR'ing a combination of the following event flags:\n
* POLLIN -- There is data to read.\n
* POLLOUT -- Writing is now possible, though a write larger that the available space in a socket or pipe will still block (unless O_NONBLOCK is set).\n
* POLLERR -- Error condition (only returned in revents; ignored in events).\n
* POLLRDHUP -- Stream socket peer closed connection, or shut down writing half of connection.\n
* POLLHUP -- Hang up (only returned in revents; ignored in events). Note that when reading from a channel such as a stream socket, this event
* merely indicates that the peer closed its end of the channel. Subsequent reads from the channel will return 0 (end of file) only after all outstanding
* data in the channel has been consumed.\n\n
*
* @param    fds  [IN/OUT]  The field fd contains a file descriptor for an open file. The field events is an input parameter, a bit mask specifying
* the events the application is interested in for the file descriptor fd. This field can be specified as zero, in which case the only events that can be
* returned in revents are POLLHUP and POLLERR. The field revents is an output parameter, filled by LiteOS kernel with the events that actually occurred.
* The bits returned in revents can include any of those specified in events, or one of the values POLLERR or POLLHUP.
* @param    nfds   [IN]  the number of items in the fds.
* @param    timeout  [IN]  the number of milliseconds that the poll should block waiting for a file descriptor to become ready. The call will block until
* either a file descriptor becomes ready or the timeout expires. If the value of timeout is 0, poll just check the file descriptors and return immediately,
* even if no file descriptors are ready. If the value of timeout is -1, poll blocks until a requested event occurs.
*
* @attention
* <ul>
* <li>Unlike Linux or other operation system, LiteOS does not support signal mechanism, so the poll function can't be interrupted by signal.</li>
* <li>Other events which supported on Linux, such as POLLRDNORM, POLLWRNORM, POLLRDBAND, POLLWRBAND and POLLNVAL, are not supported on LiteOS.</li>
* <li>On LiteOS, the user must make sure all the file descriptors supplied in fds are valid, else the poll function returns failure immediately. On Linux or
* other platform, if the file descriptpr is negative or invalid, the corresponding events field is ignored and the revents field returns zero.</li>
* <li>It is recommended that the poll function is perferred than the select as the impelmentation of select is based on the pool, so the poll function is more efficient.</li>
* <li>If a file descriptor being monitored by poll is closed in another thread, the result is unspecified. On some UNIX systems, poll unblocks and returns
* with an indication that the file descriptor is ready. On LiteOS, closing the file descriptor in another thread has no effect on poll.  In summary,
* any application that relies on a particular behavior in this scenario must be considered buggy.</li>
* <li>The timeout will be rounded up to the system clock granularity, on LiteOS, it's the system scheduling tick. So the minimal poll timeout is one
* scheduling tick on LiteOS.</li>
* <li>LiteOS does not support TCP urgent data(also used as the out-of-band data), so user cannot use the poll function with POLLPRI to examine the TCP urgent data.</li>
* </ul>
*
* @retval    #>=0   On success, a positive number is returned; this is the number of structures which have nonzero revents fields (in other words,
* those descriptors with events or errors reported).  A value of 0 indicates that the call timed out and no file descriptors were ready.
* @retval    #-1   On failure, -1 is returned, and errno is set to indicate the error.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: One of the file descriptor supplied in fds is invalid.</li>
* <li><b>EINVAL</b>: The fds is a null pointer.</li>
* <li><b>ENOMEM</b>: There was no space to allocate file descriptor tables.</li>
* <li><b>ENOSYS</b>: One or more of the file descriptor sets specified a file descriptor don't support poll operation</li>
* </ul>
*
* @par Dependency:
* <ul><li>poll.h</li></ul>
*
* @see  accept | connect | select | read | recv | send | write
*
* @since Huawei LiteOS V100R001C00
*/

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
int ppoll(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*);

int __poll_chk(struct pollfd*, nfds_t, int, size_t);
int __poll_real(struct pollfd*, nfds_t, int) __RENAME(poll);
__errordecl(__poll_too_small_error, "poll: pollfd array smaller than fd count");

int __ppoll_chk(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*, size_t);
int __ppoll_real(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*) __RENAME(ppoll);
__errordecl(__ppoll_too_small_error, "ppoll: pollfd array smaller than fd count");

#if defined(__BIONIC_FORTIFY)

__BIONIC_FORTIFY_INLINE
int poll(struct pollfd* fds, nfds_t fd_count, int timeout) {
#if defined(__clang__)
  return __poll_chk(fds, fd_count, timeout, __bos(fds));
#else
  if (__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE) {
    if (!__builtin_constant_p(fd_count)) {
      return __poll_chk(fds, fd_count, timeout, __bos(fds));
    } else if (__bos(fds) / sizeof(*fds) < fd_count) {
      __poll_too_small_error();
    }
  }
  return __poll_real(fds, fd_count, timeout);
#endif
}

__BIONIC_FORTIFY_INLINE
int ppoll(struct pollfd* fds, nfds_t fd_count, const struct timespec* timeout, const sigset_t* mask) {
#if defined(__clang__)
  return __ppoll_chk(fds, fd_count, timeout, mask, __bos(fds));
#else
  if (__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE) {
    if (!__builtin_constant_p(fd_count)) {
      return __ppoll_chk(fds, fd_count, timeout, mask, __bos(fds));
    } else if (__bos(fds) / sizeof(*fds) < fd_count) {
      __ppoll_too_small_error();
    }
  }
  return __ppoll_real(fds, fd_count, timeout, mask);
#endif
}

#endif


#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */

#endif /* _POLL_H_ */
